// module ysyx_050369_Smultiplier (
//     input               clk,
//     input               rst,
//     input               mul_valid,
//     input               flush,//    为高表示取消乘法
//     input               mulw,//为高表示是 32 位乘法
//     input   [1:0]       mul_signed,//2’b11（signed x signed）；2’b10（signed x unsigned）；2’b00（unsigned x unsigned）；
//     input   [63:0]      multiplicand,
//     input   [63:0]      multiplier,
//     output reg          mul_ready,
//     output reg          out_valid,
//     output reg [63:0]   result_hi,
//     output reg [63:0]   result_lo
// );
//     reg [3:0] state,next_state;
//     reg [127:0]res;
//     wire [63:0]multiplicand_64 ;
//     wire [63:0]multiplier_64 ;
//     wire [31:0]multiplicand_32 ;
//     wire [31:0]multiplier_32 ;
//     reg [31:0] cycle;
//     reg [63:0] multiplier_temp;
//     reg [127:0] multiplicand_temp;
//     reg [31:0] cnt;
//     reg        sign;
//     reg [130:0] input_buffer [1:0];
//     reg [127:0] out_buffer   [1:0];
//     wire [1:0] hit;
//     wire    hit_num;
//     always @(posedge mul_valid) begin
        
//     end
//     assign multiplicand_64  = {multiplicand[63],~multiplicand[62:0]}+1;
//     assign multiplier_64    = {multiplier[63],~multiplier[62:0]}+1;
//     assign multiplicand_32  = {multiplicand[31],~multiplicand[30:0]}+1;
//     assign multiplier_32    = {multiplier[31],~multiplier[30:0]}+1;
//     parameter IDLE=0,READY=1,RUN=2,FIN=3,RES=4,HIT_RES=5;
//     genvar j;
//     integer i;
//     generate
//         for (j = 0; j< 2;j++ ) begin
//             assign hit[j] = ({mulw,mul_signed,multiplicand,multiplier} == input_buffer[j]) ? 1'b1 :1'b0;
//         end
//     endgenerate

//     always @(posedge clk ) begin
//         if (rst || flush)  state <= IDLE;
//         else  state <= next_state;
//     end
//     always @(*) begin
//         case (state)
//             IDLE: if(mul_valid) begin
//                 next_state = hit > 0 ?HIT_RES: READY;
//             end
                
//             READY: next_state = RUN;
//             RUN:begin
//                if (cnt == cycle)  next_state = FIN;
//                else next_state = RUN;
//             end
//             FIN:next_state = RES;
//             RES:next_state = IDLE;
//             HIT_RES:next_state = IDLE;
//             default: begin end
//         endcase
//     end
//     always @(posedge clk ) begin
//         if (rst) begin
//             res             <= 'b0;
//             multiplier_temp <= 'b0;
//             cycle           <= 'b0;
//             multiplicand_temp <= 'b0;
//             mul_ready       <= 'b1;
//             out_valid       <= 'b0;
//             result_hi       <= 'b0;
//             result_lo       <= 'b0;
//             cnt             <= 'b0;
//             sign            <= 'b0;
//             for (i = 0; i< 2; i++ ) begin
//                 input_buffer[i] <= 131'b0;
//                 out_buffer[i]   <= 128'b0;
//             end
//         end
//         else begin
//             case (next_state)
//                 IDLE:begin
//                     res             <= 'b0;
//                     multiplier_temp <= 'b0;
//                     cycle           <= 'b0;
//                     multiplicand_temp <= 'b0;
//                     mul_ready       <= 'b1;
//                     out_valid       <= 'b0;
//                     cnt             <= 'b0;
//                     sign            <= 'b0;
//                 end 
//                 READY:begin
//                     mul_ready       <= 'b0;
//                     case ({mulw,mul_signed})
//                         3'b000:begin
//                             multiplicand_temp<= {64'b0,multiplicand};
//                             multiplier_temp <= multiplier;
//                             cycle           <= 32'd64;
//                             sign            <= 'b0;
//                         end 
//                         3'b010:begin
//                             multiplicand_temp<= multiplicand_64[63]?{65'b0,multiplicand_64[62:0]}:{64'b0,multiplicand};
//                             multiplier_temp <= multiplier;
//                             cycle           <= 32'd64;
//                             sign            <= multiplicand[63];
//                         end 
//                         3'b011:begin
//                             multiplicand_temp<= multiplicand_64[63]?{65'b0,multiplicand_64[62:0]}:{64'b0,multiplicand};
//                             multiplier_temp <= multiplier_64[63]?{1'b0,multiplier_64[62:0]}:multiplier;
//                             cycle           <= 32'd63;
//                             sign            <= multiplicand[63]^multiplier[63];
//                         end 
//                         3'b100:begin
//                             multiplicand_temp<= {96'b0,multiplicand[31:0]};
//                             multiplier_temp <= {32'b0,multiplier[31:0]};
//                             cycle           <= 32'd32;
//                             sign            <= 'b0;
//                         end 
//                         3'b110:begin
//                             multiplicand_temp<= multiplicand_32[31]?{96'b0,multiplicand_32}:{96'b0,multiplicand[31:0]};
//                             multiplier_temp <= {32'b0,multiplier[31:0]};
//                             cycle           <= 32'd32;
//                             sign            <= multiplicand[31];
//                         end 
//                         3'b111:begin
//                             multiplicand_temp<= multiplicand_32[31]?{96'b0,multiplicand_32}:{96'b0,multiplicand[31:0]};
//                             multiplier_temp <= multiplier_32[31]?{33'b0,multiplier_32[30:0]}:{32'b0,multiplier[31:0]};
//                             cycle           <= 32'd31;
//                             sign            <= multiplicand[31]^multiplier[31];
                            
//                         end 
//                         default: begin end
//                     endcase
                    
//                 end
//                 RUN:begin
//                     if (multiplier_temp[0]) begin
//                         res <= res+multiplicand_temp;
//                     end
//                     multiplicand_temp <=multiplicand_temp << 1;
//                     multiplier_temp <= multiplier_temp >> 1;
//                     cnt             <= cnt +1;
//                 end
//                 FIN:begin
//                     if (sign ) begin
//                         res <= ~res +1;
//                     end
//                 end
//                 RES:begin
//                     out_valid       <= 1'b1;
//                     result_lo       <= mulw?{{32{res[31]}},res[31:0]}:res[63:0];
//                     result_hi       <= res[127:64];
//                     input_buffer[0] <= {mulw,mul_signed,multiplicand,multiplier};
//                     out_buffer  [0] <= {res[127:64],{mulw?{{32{res[31]}},res[31:0]}:res[63:0]}};
//                     for (i = 1; i< 2; i++ ) begin
//                         input_buffer[i] <= input_buffer[i-1];
//                         out_buffer[i]   <= out_buffer[i-1];
//                     end
//                 end
//                 HIT_RES:begin
//                     out_valid       <= 1'b1;
//                     result_lo       <= out_buffer[hit_num][63:0];
//                     result_hi       <= out_buffer[hit_num][127:64];
//                 end
//                 default: begin end
//             endcase
//         end
//     end
//     assign hit_num  =   (hit == 2'h1)? 1'b0 :
//                         (hit == 2'h2)? 1'b1 : 1'b0;
//                         // (hit == 4'h4)? 2'b10 :
//                         // (hit == 4'h8)? 2'b11 :2'b0;
// endmodule


module ysyx_050369_Smultiplier (
    input               clk,
    input               rst,
    input               mul_valid,
    input               flush,//    为高表示取消乘法
    input               mulw,//为高表示是 32 位乘法
    input   [1:0]       mul_signed,//2’b11（signed x signed）；2’b10（signed x unsigned）；2’b00（unsigned x unsigned）；
    input   [63:0]      multiplicand,
    input   [63:0]      multiplier,
    output reg          mul_ready,
    output reg          out_valid,
    output reg[63:0]    result_hi,
    output reg[63:0]    result_lo
);
    reg [3:0] state,next_state;
    reg [127:0]res;
    reg [63:0] multiplicand_ ;
    reg [31:0] cycle;
    reg [63:0] multiplier_temp;
    reg [127:0] multiplicand_temp;
    reg [31:0] cnt;
    reg [130:0] input_buffer [1:0];
    reg [127:0] out_buffer   [1:0];
    wire [1:0] hit;
    wire    hit_num;
    parameter IDLE=0,READY=1,RUN=2,FIN=3,RES=4,HIT_RES=5;
    wire multiplier_sign,multiplicand_sign;
    assign multiplier_sign   = (mulw?multiplier[32]  :multiplier[63]  )&& mul_signed[0];
    assign multiplicand_sign = (mulw?multiplicand[32]:multiplicand[63])&& mul_signed[1];
    genvar j;
    integer i;
    generate
        for (j = 0; j< 2;j++ ) begin
            assign hit[j] = ({mulw,mul_signed,multiplicand,multiplier} == input_buffer[j]) ? 1'b1 :1'b0;
        end
    endgenerate

    always @(posedge clk ) begin
        if (rst || flush)  state <= IDLE;
        else  state <= next_state;
    end
    always @(*) begin
        case (state)
            IDLE: if(mul_valid) begin
                next_state = hit > 0 ?HIT_RES: READY;
            end
                
            READY: next_state = RUN;
            RUN:begin
               if (cnt == cycle)  next_state = FIN;
               else next_state = RUN;
            end
            FIN:next_state = RES;
            RES:next_state = IDLE;
            HIT_RES:next_state = IDLE;
            default: next_state = IDLE;
        endcase
    end
    always @(posedge clk ) begin
        if (rst) begin
            res             <= 'b0;
            multiplier_temp <= 'b0;
            cycle           <= 'b0;
            multiplicand_temp <= 'b0;
            out_valid       <= 'b0;
            cnt             <= 'b0;
            multiplicand_   <= 'b0;
            for (i = 0; i< 2; i++ ) begin
                input_buffer[i] <= 131'b0;
                out_buffer[i]   <= 128'b0;
            end
            result_lo       <= 'b0;
            result_hi       <= 'b0;
            mul_ready       <= 1'b1;
        end
        else begin
            case (next_state)
                IDLE:begin
                    res             <= 'b0;
                    multiplier_temp <= 'b0;
                    cycle           <= 'b0;
                    multiplicand_temp <= 'b0;
                    out_valid       <= 'b0;
                    cnt             <= 'b0;
                    mul_ready       <= 1'b1;
                    multiplicand_   <= 'b0;
                end 
                READY:begin
                    mul_ready       <= 1'b0;
                    cycle            <= mulw?32'd31:32'd63;
                    multiplicand_temp<= mulw?{64'b0,{32{multiplicand_sign}},multiplicand[31:0]}:{{64{multiplicand_sign}},multiplicand};
                    multiplier_temp  <= multiplier;
                    multiplicand_    <= ~multiplicand+1;
                end
                RUN:begin
                    if (multiplier_temp[0]) begin
                        res <= res+multiplicand_temp;
                    end
                    multiplicand_temp <={multiplicand_temp[126:0] ,1'b0};
                    multiplier_temp <= {1'b0,multiplier_temp[63:1]} ;
                    cnt             <= cnt +1;
                end
                FIN:begin
                    if (multiplier_sign ) begin
                        res <= res +(mulw?{65'b0,multiplicand_[31:0],31'b0}:{1'b0,multiplicand_,63'b0});
                    end
                    else begin
                        if (multiplier_temp[0]) begin
                            res <= res+multiplicand_temp;
                        end
                    end
                end
                RES:begin
                    out_valid       <= 1'b1;
                    // result_lo       <= mulw?{{32{res[31]}},res[31:0]}:res[63:0];
                    result_lo       <= mulw?{{32{res[31]}},res[31:0]}:res[63:0];
                    result_hi       <= res[127:64];
                    input_buffer[0] <= {mulw,mul_signed,multiplicand,multiplier};
                    out_buffer  [0] <= {res[127:64],mulw?{{32{res[31]}},res[31:0]}:res[63:0]};
                    input_buffer[1] <= input_buffer[0];
                    out_buffer  [1] <= out_buffer[0];
                end
                HIT_RES:begin
                    out_valid       <= 1'b1;
                    result_lo       <= out_buffer[hit_num][63:0];
                    result_hi       <= out_buffer[hit_num][127:64];
                end
                default: begin end
            endcase
        end
    end
    assign hit_num  =   (hit == 2'h1)? 1'b0 :
                        (hit == 2'h2)? 1'b1 : 1'b0;
endmodule